{
 "cells": [
  {
   "cell_type": "code",
   "id": "initial_id",
   "metadata": {
    "collapsed": true,
    "ExecuteTime": {
     "end_time": "2025-02-24T12:36:54.344925Z",
     "start_time": "2025-02-24T12:36:54.338605Z"
    }
   },
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "    \n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42\n"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=12, micro=3, releaselevel='final', serial=0)\n",
      "matplotlib 3.10.0\n",
      "numpy 1.26.4\n",
      "pandas 2.2.3\n",
      "sklearn 1.6.1\n",
      "torch 2.6.0+cu118\n",
      "cuda:0\n"
     ]
    }
   ],
   "execution_count": 3
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-24T12:36:54.485374Z",
     "start_time": "2025-02-24T12:36:54.345969Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from torchvision import datasets\n",
    "from torchvision.transforms import ToTensor\n",
    "from torch.utils.data import random_split\n",
    "\n",
    "# fashion_mnist图像分类数据集\n",
    "train_ds = datasets.FashionMNIST(\n",
    "    root=\"data\",\n",
    "    train=True,\n",
    "    download=True,\n",
    "    transform=ToTensor()\n",
    ")\n",
    "\n",
    "test_ds = datasets.FashionMNIST(\n",
    "    root=\"data\",\n",
    "    train=False,\n",
    "    download=True,\n",
    "    transform=ToTensor()\n",
    ")\n",
    "\n",
    "# torchvision 数据集里没有提供训练集和验证集的划分\n",
    "# 这里用 random_split 按照 11 : 1 的比例来划分数据集\n",
    "train_ds, val_ds = random_split(train_ds, [55000, 5000], torch.Generator().manual_seed(seed))"
   ],
   "id": "f7970b29db6f0ac3",
   "outputs": [],
   "execution_count": 4
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-24T12:36:54.500140Z",
     "start_time": "2025-02-24T12:36:54.486378Z"
    }
   },
   "cell_type": "code",
   "source": [
    "img, label = train_ds[0]\n",
    "img.shape, label"
   ],
   "id": "ecce51af4eeac742",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([1, 28, 28]), 9)"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 5
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-24T12:37:06.207617Z",
     "start_time": "2025-02-24T12:37:06.203812Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from torch.utils.data.dataloader import DataLoader\n",
    "\n",
    "batch_size = 32\n",
    "# 从数据集到dataloader\n",
    "train_loader = DataLoader(train_ds, batch_size=batch_size, shuffle=True, num_workers=4)\n",
    "val_loader = DataLoader(val_ds, batch_size=batch_size, shuffle=False, num_workers=4)\n",
    "test_loader = DataLoader(test_ds, batch_size=batch_size, shuffle=False, num_workers=4)"
   ],
   "id": "f3d7628343e58638",
   "outputs": [],
   "execution_count": 6
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-24T14:15:04.959761Z",
     "start_time": "2025-02-24T14:15:04.941719Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class CNN(nn.Module):\n",
    "    def __init__(self, activation=\"relu\"):\n",
    "        super(CNN, self).__init__()\n",
    "        self.activation = F.relu if activation == \"relu\" else F.selu\n",
    "        #输入通道数，图片是灰度图，所以是1，图片是彩色图，就是3，输出通道数，就是卷积核的个数（32,1,28,28）\n",
    "        #输入x(32,1,28,28) 输出x(32,32,28,28)\n",
    "        self.conv1 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3, padding=1)\n",
    "        #输入x(32,32,28,28) 输出x(32,32,28,28)\n",
    "        self.conv2 = nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=1)\n",
    "        self.pool = nn.MaxPool2d(2, 2) #池化不能够改变通道数，池化核大小为2（2*2），步长为2  (28-2)//2+1=14\n",
    "        self.conv3 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, padding=1)\n",
    "        self.conv4 = nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, padding=1)\n",
    "        self.conv5 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, padding=1)\n",
    "        self.conv6 = nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, padding=1)\n",
    "        self.flatten = nn.Flatten()\n",
    "        # input shape is (28, 28, 1) so the fc1 layer in_features is 128 * 3 * 3\n",
    "        self.fc1 = nn.Linear(128 * 3 * 3, 128)\n",
    "        self.fc2 = nn.Linear(128, 10) #输出尺寸（32,10）\n",
    "\n",
    "        self.init_weights()\n",
    "\n",
    "    def init_weights(self):\n",
    "        \"\"\"使用 xavier 均匀分布来初始化全连接层、卷积层的权重 W\"\"\"\n",
    "        for m in self.modules():\n",
    "            if isinstance(m, (nn.Linear, nn.Conv2d)):\n",
    "                nn.init.xavier_uniform_(m.weight)\n",
    "                nn.init.zeros_(m.bias)\n",
    "\n",
    "    def forward(self, x):\n",
    "        act = self.activation\n",
    "        x = self.pool(act(self.conv2(act(self.conv1(x))))) # 1 * 28 * 28 -> 32 * 14 * 14\n",
    "        print(x.shape)\n",
    "        x = self.pool(act(self.conv4(act(self.conv3(x))))) # 32 * 14 * 14 -> 64 * 7 * 7\n",
    "        # print(x.shape)\n",
    "        x = self.pool(act(self.conv6(act(self.conv5(x))))) # 64 * 7 * 7 -> 128 * 3 * 3\n",
    "        # print(x.shape)\n",
    "        x = self.flatten(x) # 128 * 3 * 3 ->1152\n",
    "        x = act(self.fc1(x)) # 1152 -> 128\n",
    "        x = self.fc2(x) # 128 -> 10\n",
    "        return x\n",
    "\n",
    "\n",
    "for idx, (key, value) in enumerate(CNN().named_parameters()):\n",
    "    print(f\"{key}\\tparamerters num: {np.prod(value.shape)}\") # 打印模型的参数信息\n"
   ],
   "id": "2ac662dbe6ad77f1",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "conv1.weight\tparamerters num: 288\n",
      "conv1.bias\tparamerters num: 32\n",
      "conv2.weight\tparamerters num: 9216\n",
      "conv2.bias\tparamerters num: 32\n",
      "conv3.weight\tparamerters num: 18432\n",
      "conv3.bias\tparamerters num: 64\n",
      "conv4.weight\tparamerters num: 36864\n",
      "conv4.bias\tparamerters num: 64\n",
      "conv5.weight\tparamerters num: 73728\n",
      "conv5.bias\tparamerters num: 128\n",
      "conv6.weight\tparamerters num: 147456\n",
      "conv6.bias\tparamerters num: 128\n",
      "fc1.weight\tparamerters num: 147456\n",
      "fc1.bias\tparamerters num: 128\n",
      "fc2.weight\tparamerters num: 1280\n",
      "fc2.bias\tparamerters num: 10\n"
     ]
    }
   ],
   "execution_count": 17
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-24T14:15:07.021121Z",
     "start_time": "2025-02-24T14:15:07.017119Z"
    }
   },
   "cell_type": "code",
   "source": [
    "def count_parameters(model): #计算模型总参数量\n",
    "    return sum(p.numel() for p in model.parameters() if p.requires_grad)"
   ],
   "id": "7df2139bd73a7b01",
   "outputs": [],
   "execution_count": 18
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-24T14:15:13.778592Z",
     "start_time": "2025-02-24T14:15:13.761950Z"
    }
   },
   "cell_type": "code",
   "source": "count_parameters(CNN())",
   "id": "22d9f92fe5e562f8",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "435306"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 19
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-24T14:17:33.587942Z",
     "start_time": "2025-02-24T14:17:33.559112Z"
    }
   },
   "cell_type": "code",
   "source": [
    "#练习不同尺寸的卷积核，padding，stride的效果\n",
    "class CNN1(nn.Module):\n",
    "    def __init__(self, activation=\"relu\"):\n",
    "        super().__init__()\n",
    "        self.activation = F.relu if activation == \"relu\" else F.selu\n",
    "        #输入通道数，图片是灰度图，所以是1，图片是彩色图，就是3，输出通道数，就是卷积核的个数（32,1,28,28）\n",
    "        self.conv1 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3,padding=0,stride=1)\n",
    "        #输入x(32,32,28,28) 输出x(32,32,28,28)\n",
    "        self.conv2 = nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=1)\n",
    "        self.pool = nn.MaxPool2d(2, 2) #池化核大小为2（2*2），步长为2\n",
    "        self.conv3 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, padding=1)\n",
    "        self.conv4 = nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, padding=1)\n",
    "        self.conv5 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, padding=1)\n",
    "        self.conv6 = nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, padding=1)\n",
    "        self.flatten = nn.Flatten()\n",
    "        # input shape is (28, 28, 1) so the fc1 layer in_features is 128 * 3 * 3\n",
    "        self.fc1 = nn.Linear(128 * 3 * 3, 128)\n",
    "        self.fc2 = nn.Linear(128, 10) #输出尺寸（32,10）\n",
    "\n",
    "        self.init_weights()\n",
    "\n",
    "    def init_weights(self):\n",
    "        \"\"\"使用 xavier 均匀分布来初始化全连接层、卷积层的权重 W\"\"\"\n",
    "        for m in self.modules():\n",
    "            if isinstance(m, (nn.Linear, nn.Conv2d)):\n",
    "                nn.init.xavier_uniform_(m.weight)\n",
    "                nn.init.zeros_(m.bias)\n",
    "\n",
    "    def forward(self, x):\n",
    "        act = self.activation\n",
    "        x=act(self.conv1(x)) # 1 * 28 * 28 -> 32 * 28 * 28\n",
    "        print(x.shape)\n",
    "        # x=act(self.conv2(x)) # 32 * 28 * 28 -> 32 * 28 * 28\n",
    "        # print(x.shape)\n",
    "        # x = self.pool(x) # 32 * 28 * 28 -> 32 * 14 * 14\n",
    "        # print(x.shape)\n",
    "        # x=act(self.conv3(x)) # 32 * 14 * 14 -> 64 * 14 * 14\n",
    "        # print(x.shape)\n",
    "        # x=act(self.conv4(x)) # 64 * 14 * 14 -> 64 * 14 * 14\n",
    "        # print(x.shape)\n",
    "        # x = self.pool(x) # 32 * 14 * 14 -> 64 * 7 * 7\n",
    "        # print(x.shape)\n",
    "        # x=act(self.conv5(x)) # 64 * 7 * 7 -> 128 * 7 * 7\n",
    "        # print(x.shape)\n",
    "        # x=act(self.conv6(x)) # 128 * 7 * 7 -> 128 * 7 * 7\n",
    "        # print(x.shape)\n",
    "        # x = self.pool(x) # 128 * 7 * 7 -> 128 * 3 * 3\n",
    "        # print(x.shape)\n",
    "        # x = self.flatten(x) # 128 * 3 * 3 ->1152\n",
    "        # x = act(self.fc1(x)) # 1152 -> 128\n",
    "        # x = self.fc2(x) # 128 -> 10\n",
    "        return x\n",
    "activation = \"relu\"\n",
    "model = CNN1(activation)\n",
    "# model.to(device)\n",
    "img = torch.randn(1, 1, 28, 28)\n",
    "model(img)"
   ],
   "id": "a5ee97f50a64d4ba",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([1, 32, 26, 26])\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "tensor([[[[0.1298, 0.0000, 0.0000,  ..., 0.0951, 0.0000, 0.2195],\n",
       "          [0.3420, 0.0000, 0.0000,  ..., 0.1708, 0.0808, 0.1102],\n",
       "          [0.4914, 0.2078, 0.0000,  ..., 0.1309, 0.0000, 0.0746],\n",
       "          ...,\n",
       "          [0.6115, 0.0000, 0.0401,  ..., 0.0000, 0.0000, 0.0538],\n",
       "          [0.4574, 0.0000, 0.2194,  ..., 0.0000, 0.0000, 0.0852],\n",
       "          [0.0000, 0.0000, 0.0000,  ..., 0.1617, 0.4188, 0.2009]],\n",
       "\n",
       "         [[0.0000, 0.4062, 0.0000,  ..., 0.0636, 0.2049, 0.0000],\n",
       "          [0.0492, 0.3723, 0.2210,  ..., 0.1943, 0.0000, 0.0520],\n",
       "          [0.3387, 0.2537, 0.2200,  ..., 0.1774, 0.2197, 0.3154],\n",
       "          ...,\n",
       "          [0.0000, 0.0346, 0.2577,  ..., 0.0000, 0.0000, 0.1366],\n",
       "          [0.0000, 0.0000, 0.0382,  ..., 0.0000, 0.0000, 0.0000],\n",
       "          [0.0256, 0.0000, 0.0000,  ..., 0.1367, 0.0000, 0.0000]],\n",
       "\n",
       "         [[0.1529, 0.1815, 0.0140,  ..., 0.0143, 0.0000, 0.0000],\n",
       "          [0.0000, 0.1303, 0.0000,  ..., 0.0000, 0.2034, 0.1782],\n",
       "          [0.0101, 0.2548, 0.1254,  ..., 0.0000, 0.0000, 0.0000],\n",
       "          ...,\n",
       "          [0.2619, 0.0000, 0.0000,  ..., 0.4384, 0.0893, 0.1584],\n",
       "          [0.3567, 0.6557, 0.2778,  ..., 0.0000, 0.0000, 0.0000],\n",
       "          [0.0000, 0.0000, 0.0000,  ..., 0.0929, 0.0999, 0.0530]],\n",
       "\n",
       "         ...,\n",
       "\n",
       "         [[0.0000, 0.3640, 0.2417,  ..., 0.0000, 0.1482, 0.0000],\n",
       "          [0.0000, 0.0179, 0.2355,  ..., 0.1288, 0.1192, 0.0553],\n",
       "          [0.1320, 0.1264, 0.1836,  ..., 0.1714, 0.0095, 0.0821],\n",
       "          ...,\n",
       "          [0.0000, 0.2632, 0.1143,  ..., 0.0706, 0.0000, 0.1613],\n",
       "          [0.0009, 0.1672, 0.0372,  ..., 0.0000, 0.0000, 0.0000],\n",
       "          [0.0000, 0.0000, 0.1317,  ..., 0.0000, 0.0000, 0.0000]],\n",
       "\n",
       "         [[0.0000, 0.2446, 0.0000,  ..., 0.2514, 0.0453, 0.0000],\n",
       "          [0.5991, 0.3471, 0.0643,  ..., 0.0000, 0.0000, 0.0225],\n",
       "          [0.0000, 0.0648, 0.0000,  ..., 0.0918, 0.5342, 0.3485],\n",
       "          ...,\n",
       "          [0.0000, 0.0642, 0.1131,  ..., 0.0000, 0.0000, 0.0000],\n",
       "          [0.0000, 0.0000, 0.0000,  ..., 0.4629, 0.0000, 0.0000],\n",
       "          [0.3012, 0.0000, 0.0000,  ..., 0.1748, 0.0000, 0.3373]],\n",
       "\n",
       "         [[0.1089, 0.5249, 0.0000,  ..., 0.0000, 0.0116, 0.0673],\n",
       "          [0.0000, 0.0000, 0.3899,  ..., 0.0000, 0.0000, 0.1701],\n",
       "          [0.0000, 0.2799, 0.0000,  ..., 0.3660, 0.0000, 0.0000],\n",
       "          ...,\n",
       "          [0.2068, 0.1914, 0.0892,  ..., 0.1640, 0.1355, 0.0000],\n",
       "          [0.0230, 0.0000, 0.2201,  ..., 0.0000, 0.0586, 0.2602],\n",
       "          [0.2165, 0.3138, 0.0000,  ..., 0.0591, 0.0307, 0.0730]]]],\n",
       "       grad_fn=<ReluBackward0>)"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 21
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-24T15:39:40.475050Z",
     "start_time": "2025-02-24T15:39:40.468091Z"
    }
   },
   "cell_type": "code",
   "source": [
    "import numpy as np\n",
    "def step_function(x):\n",
    "  y = x > 0\n",
    "  return y.astype(np.int32)\n",
    "step_function(np.array([1.0, 2.0]))"
   ],
   "id": "9dac5e3f119fd992",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1, 1])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 2
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-24T15:40:40.604768Z",
     "start_time": "2025-02-24T15:40:40.598926Z"
    }
   },
   "cell_type": "code",
   "source": [
    "def step_function(x):\n",
    " return np.array(x > 0, dtype=np.int32)\n",
    "step_function(np.array([-1.0, 2.0]))"
   ],
   "id": "8633f6509fbca63d",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 4
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
